/*
 *  proposer_main.h
 */

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/time.h>
#include <event.h>
#include <evutil.h>
#include<stdbool.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<fcntl.h>

#define STRING_SIZE 1024
#define CONFIG "/home/parisa/Paxos-UDP/config/p_config.txt"

int msgs_generated=0, ENTRANCE=0, ENTRANCE_NTH=0;;
int proposer_to_multicaster_sid, PROCESS_ID, proposers_count, N, SUBMIT_PER_WAKE, MSG_ID=0, digit=0;
struct timeval tv,tv1, tv2, endTime, elapsedTime, startTime, start,end,elapsed, startTotal, endTotal, elapsedTotal;
struct event *timeoutEve, *timeoutEve1, *timeoutEve2;
int buffSize=(1024*1024*8);
int mI=0;
struct sockaddr_in server_addr;

#include "types.h"
#include "TCPconnections.h"
#include "IPread.h"
#include "generate_msgs.h"
#include "UDP.h"

int last=0, current=0;
int lastENTRANCE=0, currentENTRANCE=0;
int lastENTRANCE_NTH=0, currentENTRANCE_NTH=0;



double sending_throughput[2000];
double avg_sending[2000];
int entrance_vector[2000];
double avg_entrance[2000];
int total_time[2000];

int t_counter=0;
//------------------------------------------------------------------------------
void store_performance_in_file()
{
	FILE *f;
	char fileName[STRING_SIZE], name[STRING_SIZE];
	int i;
	strcpy(fileName, "/home/parisa/Paxos-UDP/proposer/throughput/");
   
	sprintf("name,"%d",PROCESS_ID);
	strcat(fileName, name);
	strcat(fileName,".dat");
	
	f=fopen(fileName,"a");
	fprintf(","writing to file: \n");
	for(i=0;i<t_counter;i++)
		fprintf("f,"%d %f %f\n",total_time[i],avg_sending[i], avg_entrance[i]);
	
	fclose(f);
}
//------------------------------------------------------------------------------
void th_avg()
{
	double avg_t=0, avg_e=0;
	int i;
	
	for(i=0;i<=t_counter;i++)
	  {
		  avg_t+=sending_throughput[i];
		  avg_e+=entrance_vector[i];
	  }	  
	avg_e=avg_e/(double)(t_counter+1);
	avg_t=avg_t/(double)(t_counter+1);
	//fprintf(", "AVG_S_T: %f | AVG_E: %f ", avg_t, avg_e);
	
	avg_sending[t_counter]=avg_t;
	avg_entrance[t_counter]=avg_e;
}
//------------------------------------------------------------------------------
void throughput(int sd, short event, void * arg)
{
	int temp;
	double t ;
    int msecInterval,msecTotal;
	
	gettimeofday(&endTime,NULL);
	gettimeofday(&endTotal,NULL);
	
	elapsedTime.tv_sec=endTime.tv_sec-startTime.tv_sec;
	elapsedTime.tv_usec=(endTime.tv_usec>startTime.tv_usec? endTime.tv_usec-startTime.tv_usec: startTime.tv_usec-endTime.tv_usec);
	msecInterval=1000*elapsedTime.tv_sec+elapsedTime.tv_usec/1000;
	
	
	elapsedTotal.tv_sec=endTotal.tv_sec-startTotal.tv_sec;
	elapsedTotal.tv_usec=(endTotal.tv_usec>startTotal.tv_usec? endTotal.tv_usec-startTotal.tv_usec: startTotal.tv_usec-endTotal.tv_usec);
	msecTotal=1000*elapsedTotal.tv_sec+elapsedTotal.tv_usec/1000;
	
	
	int k=1000000*elapsedTime.tv_sec+elapsedTime.tv_usec;
	current=msgs_generated;

	currentENTRANCE=ENTRANCE;
//	currentENTRANCE_NTH=ENTRANCE_NTH;
	
	temp=current-last;
	double ii=sizeof(msg);
	
	if(msecInterval!=0)
	  {
		  t=(1000*8*((double)temp*ii))/(double)(msecInterval);
		  t=t/((double)1048576);
	  }
	sending_throughput[t_counter]=t;
	
	
	
	entrance_vector[t_counter]=currentENTRANCE-lastENTRANCE;
	th_avg();

	fprintf("," | PACKETS: %d |  S_T: %f  | time: %d | entrance: %d | total Time: %d \n", temp,t, k, (currentENTRANCE-lastENTRANCE), msecTotal);
	fprintf(","========================================================================================================================================\n");
	fprintf("," entrance: %d\n",(currentENTRANCE-lastENTRANCE));
	
	last=current;
	
	lastENTRANCE=currentENTRANCE;
	
//	lastENTRANCE_NTH=currentENTRANCE_NTH;
	
	total_time[t_counter]=msecTotal;
	/*//if(msecTotal >= 1800000)
	  {
		  fprintf(","Number of sent messages: %d\n", msgs_generated);
		  store_performance_in_file();
		  sleep(20);
		  exit(-1);
	  }
	*/
	gettimeofday(&startTime,NULL);
	
	t_counter++;

	evtimer_add(timeoutEve1,&tv1);
		  	
}
//------------------------------------------------------------------------------

int main(int argc, char * argv[])
{
	//-----------------------Variables------------------------------------------
	char server_port[STRING_SIZE],server_IP[STRING_SIZE];
	int PORT;
	timeoutEve=(struct event*)malloc(sizeof(struct event));
	timeoutEve1=(struct event*)malloc(sizeof(struct event));
	timeoutEve2=(struct event*)malloc(sizeof(struct event));
	//-----------------------Get Input Parameters-------------------------------
	
	if(argc!=6)
	  {
		  fprintf(","Incompatible call to this function!Try again. \n1. First Parameter: PROCESS_ID\n2. Second Parameter: Number of Proposers\n3. Number of Messages\n4. usec\n5. SUBMIT_PER_WAKE\n");
		  exit(-1);
	  }
	
	PROCESS_ID=atoi(argv[1]);
	proposers_count=atoi(argv[2]);
	N=atoi(argv[3]);
	initialize();
	
	tv.tv_sec=0;
//	tv.tv_usec=1000;
//	SUBMIT_PER_WAKE=16;
	tv.tv_usec=atoi(argv[4]);
	SUBMIT_PER_WAKE=atoi(argv[5]);


	tv1.tv_sec=1;
	tv1.tv_usec=0;
	
	digit=proposers_count/10;
	
	/*tv2.tv_sec=0;
	tv2.tv_usec=10;
	*/
	//-----------------------Connect to Server----------------------------------
	readIPort(CONFIG,server_port, server_IP);
	fprintf(","IP:%s.\n",server_IP);
	create_udp_client_socket(server_IP, atoi(server_port));
	//create_udp_client_socket(server_IP, PORT);
	gettimeofday(&startTime,NULL);
	gettimeofday(&start,NULL);
	gettimeofday(&end,NULL);
	gettimeofday(&startTotal,NULL);
	fprintf(","after connection.\n");
	fprintf(","size of msg: %ld\n", sizeof(msg));
	//-----------------------Send MSGs -----------------------------------------
	event_init(); 
    fprintf(","========================================================================================================================================\n");
//	generate_msg();

	evtimer_set(timeoutEve,generate_msg,timeoutEve);
	if(evtimer_add(timeoutEve,&tv)<0)
	  {
		  perror("REPROPOSE EVENT :");
		  exit(-1);
	  }
	
	evtimer_set(timeoutEve1,throughput,timeoutEve1);
	if(evtimer_add(timeoutEve1,&tv1)<0)
	  {
		  perror("REPROPOSE EVENT :");
		  exit(-1);
	  }
	/*
	evtimer_set(timeoutEve2,NTH,timeoutEve2);
	if(evtimer_add(timeoutEve2,&tv2)<0)
	  {
		  perror("REPROPOSE EVENT :");
		  exit(-1);
	  }
	*/
	event_dispatch();
	//--------------------------------------------------------------------------
	
	sleep(100);
	close(proposer_to_multicaster_sid);
	
	return 1;
	
}
